<script>
  import $ from '../dfish.js'
  import {
    h
  } from 'vue'
  import FormBase from './FormBase.vue'
  import Dialog from './Dialog.vue'
  import ResizeObserver from 'resize-observer-polyfill'

  export default {
    name: 'w-combobox',
    mixins: [FormBase],
    emits: ['input', 'click:item', 'blur', 'focus'],
    props: ['multiple', 'dropper', 'picker', 'dropWidth', 'br'],
    data() {
      return {
        hasBorder: true,
        text: '',
        showSuggest: false,
        sug_timer: null,
        sensor_text: '',
        sensor_width: null,
      }
    },
    methods: {
      addVal(v) {
        let mv
        if (this.x.multiple) {
          mv = $.lodash.unionBy($.array(this.x.modelValue), $.array(v), 'value')
        } else {
          mv = [v]
        }
        $.lodash.remove(mv, m => !m || !m.text)
        this.val(mv)
      },
      complete(v) {
        this.addVal(v)
        this.clear()
        this.$nextTick(this.focus)
        return this
      },
      closeDrop() {
        this.suggest(false)
        return this
      },
      suggest(a) {
        a = a == null ? true : a
        if (a === false) {
          clearTimeout(this.sug_timer)
        }
        this.showSuggest = a
        this.warn(false)
      },
      clear() {
        this.$refs.input.value = this.sensor_text = ''
      },
      focus() {
        this.$refs.input.focus()
        this.warn(false)
        return this
      },
      oninput(e) {
        let v = e.target.value
        this.sensor_text = v
        clearTimeout(this.sug_timer)
        if (v == '') {
          this.suggest(false)
        } else {
          this.sug_timer = setTimeout(() => {
            this.suggest(true)
            this.trigger(e, v)
          }, 500)
        }
      },
      onkeydown(e) {
        let k = e.keyCode
        if (k === 8) { // 8:backspace
          if (e.target.selectionStart === 0 && e.target.selectionEnd === 0) {
            let mv = $.array(this.x.modelValue, true)
            mv.length && mv.splice(mv.length - 1, 1)
          }
        }
        //38: up, 40:down
        //if (this.showSuggest && (k == 38 || k == 40)) e.preventDefault()
      },
      onblur(e) {
        this.isFocus = false
        this.trigger('blur')
        setTimeout(() => {
          if (!this.$.isUnmounted && !this.$.isDeactivated) this.valid('blur')
        }, 100)
      },
      onfocus(e) {
        this.isFocus = true
        e.target.value && e.target.dispatchEvent(new Event('input'))
        this.trigger('focus')
      },
      clickItem(e, item) {
        e.stopPropagation()
        e.runType = 'click:item'
        this.trigger(e, item)
      },
      clickClose(e, item) {
        e.stopPropagation()
        let mv = $.array(this.x.modelValue, true)
        let i = mv.findIndex(v => v.value == item.value)
        if (i > -1) {
          mv.splice(i, 1)
          this.val(mv)
        }
      },
      clickPicker(e) {
        e.stopPropagation()
        let c = this.x.picker
        if (typeof c === 'function') c(this)
        else this.cmd(c, this.formVal())
      },
      clickDropper(e) {
        e.stopPropagation()
        this.suggest(!this.showSuggest)
        let c = this.x.dropper
        if (typeof c === 'function') c(this)
        else this.cmd(c, this.formVal())
      },
      formText() {
        return this.input_title
      },
      html_options() {
        let m = this.x.modelValue
        if (m && typeof m !== 'string') {
          return [].concat(m).map(v => h('div', {
            class: ['w-combobox-option f-flex-center', {
              'z-forbid': v.forbid
            }],
            onclick: e => this.clickItem(e, v)
          }, [h('div', {
              class: 'w-combobox-option-text f-line-1',
              title: v.text
            }, v.text),
            this.isNormal && h('div', {
              class: 'w-combobox-option-close f-i f-i-close',
              onclick: e => this.clickClose(e, v)
            })
          ]))
        }
      },
      html_var() {
        return h('div', {
          class: 'w-combobox-input-wrap'
        }, [
          h('div', {
            class: 'w-combobox-sensor',
            ref: 'sensor',
          }, this.sensor_text || (this.input_value ? null : this.input_placeholder)),
          h('input', {
            class: 'w-combobox-input',
            style: {
              width: this.sensor_width,
            },
            ref: 'input',
            oninput: this.oninput,
            onkeydown: this.onkeydown,
            onblur: this.onblur,
            onfocus: this.onfocus,
            placeholder: this.input_value ? null : this.input_placeholder,
          })
        ])
      },
      html_input() {
        return [
          this.html_input_hidden(),
          h('div', {
              class: ['w-combobox-list f-flex-1 f-flex f-oh f-height', {'f-h-gap': $.br.compat.gap}],
            },
            this.html_options(),
            this.isNormal && this.html_var(),
            this.showSuggest && h(Dialog, {
              context: this,
              ownproperty: true,
              class: 'f-dfish-dialog',
              width: Math.max($.number(this.x.dropWidth), $.bcr(this.el('main')).width),
              scrollY: true,
              autoHide: true,
              snap: {
                target: () => this.el('main'),
                position: 'v',
                indent: 1
              },
              on: {
                close: () => this.showSuggest = false
              }
            }, this.$slots)
          )
        ]
      },
      html_button() {
        let s = []
        if (this.x.dropper) {
          s.push(h('button', {
            class: 'w-input-bbr f-i f-i-caret-down',
            disabled: !this.isNormal,
            onclick: this.clickDropper
          }))
        }
        if (this.x.picker) {
          s.push(h('button', {
            class: 'w-input-bbr f-i f-i-ellipsis',
            disabled: !this.isNormal,
            onclick: this.clickPicker
          }))
        }
        return s
      }
    },
    computed: {
      validHooks() {
        return {
          validateDefault: (v) => {
            if (this.$refs.input.value)
              return this.formErr({type: 'invalid_option'})
          },
          ...this.pubValidHooks,
        }
      },
      input_value() {
        return typeof this.x.modelValue === 'string' ? this.x.modelValue : $.array(this.x.modelValue).map(v => v.value)
          .join(',')
      },
      input_title() {
        return typeof this.x.modelValue === 'string' ? '' : $.array(this.x.modelValue).map(v => v.text).join(', ')
      },
      html_class() {
        return {
          'z-br': this.x.br
        }
      },
      main_prop() {
        return this.isNormal && {
          onclick: this.focus
        }
      }
    },
    mounted() {
      if (this.isEntity && this.$refs.sensor) {
        new ResizeObserver(() => {
          if (this.$refs.sensor) {
            this.sensor_width = this.$refs.sensor.offsetWidth + 'px'
          }
        }).observe(this.$refs.sensor)
      }
    }
  }
</script>

<style>
  .w-combobox-list {
    padding: 2px 3px;
    box-sizing: border-box;
    align-items: center;
    --w-compat-gap: 3px;
    gap: var(--w-compat-gap);
  }
  
  .w-combobox-list.f-h-gap {
    padding: 1px 3px;
  }
  
  .w-combobox-list.f-h-gap>* {
    margin-top: 1px;
    margin-bottom: 1px;
  }

  .w-combobox-list>.w-combobox-input-wrap:first-child {
    padding-left: 5px;
  }

  .w-combobox-input-wrap {
    display: flex;
  }

  .w-combobox-sensor {
    position: absolute;
    visibility: hidden;
    z-index: -1;
    white-space: pre-wrap; 
  }

  .w-combobox-input {
    min-width: 14px;
    width: 14px;
    background: transparent;
    border: 0;
  }

  .w-combobox-option {
    position: relative;
    height: 26px;
    border: 1px solid #e6e6e6;
    background: #f8f8f8;
    gap: 5px;
    padding: 0 5px;
    background: #f8f8f8;
    box-sizing: border-box;
    max-width: calc(100% - 21px);
  }

  .w-combobox-option.z-forbid .w-combobox-option-text {
    text-decoration: line-through;
  }

  .w-combobox-option-close {
    color: #aaa;
    font-size: 12px;
    line-height: 0;
    transform: translateY(1px);
    cursor: pointer;
  }

  .w-combobox-option-close:hover {
    color: #f00;
  }

  .w-combobox.z-ds .w-combobox-option {
    border-color: #d0d0d0;
    background: transparent;
  }

  .w-combobox.z-ds .w-combobox-option ._s {
    padding-right: 7px
  }

  .w-combobox.z-br .w-combobox-list {
    flex-wrap: wrap;
  }
</style>
